package de.tum.in.eist.poll.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import de.tum.in.eist.poll.shared.*;

import java.util.*;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 * This class works as the controller of the application,
 * i.e. it creates the views and handles the eventflow + all RPC calls.
 */
public class EIST_POLL implements EntryPoint {
	// We need to store the currently logged in user and currently viewed lecture.
	private User user;
	private Lecture lecture;
	// The RPC object.
	private PollServiceAsync poll_service;
	
	// The three screens of the application.
	private LoginScreen login_screen;
	private LectureScreen lecture_screen;
	private FeedbackScreen feedback_screen;
	
	// We need to remember the number of feedback submitted for the current lecture,
	// so that we can decide whether the feedback screen needs to be refreshed.
	private int feedback_count;
	
	// Callbacks that handle responses to asynchronous RPCs.
	private AsyncCallback<User> get_login_callback;
	private AsyncCallback<List<Lecture>> get_lecture_callback;
	private AsyncCallback<List<Feedback>> get_feedback_callback;
	private AsyncCallback<String> submit_feedback_callback;
	private AsyncCallback<Integer> get_feedback_count_callback;
	
	/**
	 * Displays the login screen.
	 */
	public void showLoginScreen() {
		hide_all();
		login_screen.show();
	}
	
	/**
	 * Displays the lecture screen for a specific user.
	 */
	public void showLectureScreen(User user_to_show) {
		hide_all();
		if(user_to_show != null) user = user_to_show;
		if(user != null) poll_service.requestLectures(user, get_lecture_callback);
	}
	
	/**
	 * Displays the feedback screen for a specific lecture.
	 */
	public void showFeedbackScreen(Lecture lecture_to_show) {
		hide_all();
		lecture = lecture_to_show;
		poll_service.requestFeedback(lecture, get_feedback_callback);
	}

	/**
	 * This method gets called periodically to update the feedback screen if something changed.
	 */
	public void refreshFeedbackScreen() {
		poll_service.requestFeedbackCount(lecture, get_feedback_count_callback);
	}

	/**
	 * Hides all screens.
	 */
	public void hide_all() {
		if(login_screen != null) login_screen.hide();
		if(lecture_screen != null) lecture_screen.hide();
		if(feedback_screen != null) feedback_screen.hide();
	}
	
	/**
	 * Called by the login screen when the user presses the login button.
	 */
	public void login(String user, String password) {
		poll_service.login(user, password, get_login_callback);
	}
	
	/**
	 * Called by the feedback screen when the user submits his feedback.
	 */
	public void submitFeedback(int rating, String positive, String negative) {
		poll_service.submitFeedback(new Feedback(lecture, (Student)user, rating, negative, positive), submit_feedback_callback);
	}

	/**
	 * This is the entry point method.
	 */
	public void onModuleLoad() {
		// We need to access the 'this' pointer from anonymous inner classes.
		final EIST_POLL that = this;
		// Instanciate the RPC object.
		poll_service = (PollServiceAsync)GWT.create(PollService.class);
		
		// Setting up event handlers for RPC.
		
		// Called in response to the login call.
		get_login_callback = new AsyncCallback<User>() {
			@Override
			public void onSuccess(User result) {
				showLectureScreen(result);
			}

			public void onFailure(Throwable caught) {
				Window.alert(caught.getMessage());
			}
		};
		
		// Called after requesting lectures from the server.
		get_lecture_callback = new AsyncCallback<List<Lecture>>() {
			@Override
			public void onSuccess(List<Lecture> result) {
				lecture_screen.SetLectures(result, that);
				lecture_screen.show();
			}
			
			@Override
			public void onFailure(Throwable caught) {
				Window.alert(caught.getMessage());
			}
		};
		
		// Response handler to the requestFeedback RPC call. 
		get_feedback_callback = new AsyncCallback<List<Feedback>>() {
			@Override
			public void onSuccess(List<Feedback> result) {
				if(result == null) result = new ArrayList<Feedback>();
				feedback_count = result.size();
				feedback_screen.updateFeedback(result, user);
				feedback_screen.show();
			}
			
			@Override
			public void onFailure(Throwable caught) {
				Window.alert(caught.getMessage());
			}
		};
		
		// Refresh the feedback screen after the user committed their feedback.
		submit_feedback_callback = new AsyncCallback<String>() {
			@Override
			public void onSuccess(String result) {
				showFeedbackScreen(lecture);
			}
			
			@Override
			public void onFailure(Throwable caught) {
				Window.alert(caught.getMessage());
			}
		};

		// Initialize the feedback count to a sensible value.
		feedback_count = 0;
		// Refresh the feedback screen if there is new feedback to show. 
		get_feedback_count_callback = new AsyncCallback<Integer>() {
			@Override
			public void onSuccess(Integer result) {
				if(result > feedback_count && lecture != null) {
					showFeedbackScreen(lecture);
				}
			}
			
			@Override
			public void onFailure(Throwable caught) {
				
			}
		};

		// Create the screens and show the login screen per default.
		login_screen = new LoginScreen(this);
		lecture_screen = new LectureScreen(this);
		feedback_screen = new FeedbackScreen(this);
		showLoginScreen();
	}
}
